#include "udpServer.hpp"
#include "onlineUser.hpp"

#include <memory>
#include <fstream>
#include <unordered_map>
#include <signal.h>

using namespace std;
using namespace Server;

// const std::string dictTxt = "./dict.txt"; // 配置文件
// unordered_map<string, string> dict;

static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}

// static bool cutString(const string &target, string *s1, string *s2, const string &sep)
// {
//     auto pos = target.find(sep);
//     if (pos == string::npos)
//     {
//         return false;
//     }
//     // 切割子串
//     // banana:香蕉
//     *s1 = target.substr(0, pos);           //[)
//     *s2 = target.substr(pos + sep.size()); //[)
//     return true;
// }

// static void initDict()
// {
//     ifstream in(dictTxt, std::ios::binary); // 以二进制打开文件
//     if (!in.is_open())
//     {
//         cerr << "open file" << dictTxt << " error" << endl;
//         exit(OPEN_ERR);
//     }
//     string line;
//     string key, value;
//     while (getline(in, line))
//     {
//         // cout << line << endl;
//         //  切割
//         if (cutString(line, &key, &value, ":"))
//         {
//             dict.insert(make_pair(key, value));
//         }
//     }
//     in.close();
//     cout << "load dict success" << endl;
// }
// // 热加载：可以不重启服务器，修改配置文件
// static void reload(int signo)
// {
//     (void)signo;
//     initDict();
// }
// static void debugPrint()
// {
//     for (auto &dt : dict)
//     {
//         cout << dt.first << " # " << dt.second << endl;
//     }
// }
// // demo1
// void handlerMessage(int sockfd, string clientip, uint16_t clientport, string message)
// {
//     // 可以对message进行特定业务的处理，不需要关心message是怎么来的 server通信和业务逻辑解耦了！
//     // 婴儿版的业务逻辑
//     string respon_message;
//     auto iter = dict.find(message);
//     if (iter == dict.end())
//     {
//         respon_message = "unknow";
//     }
//     else
//     {
//         respon_message = iter->second;
//     }
//     // 开始返回，返回给Client客户端
//     struct sockaddr_in client;
//     bzero(&client, 0);
//     client.sin_family = AF_INET;
//     client.sin_addr.s_addr = inet_addr(clientip.c_str());
//     client.sin_port = htons(clientport);
//     sendto(sockfd, respon_message.c_str(), respon_message.size(), 0, (struct sockaddr *)&client, sizeof(client));
// }

// // demo2
// void execCommond(int sockfd, string clientip, uint16_t clientport, string cmd)
// {
//     string respon_message;
//     FILE *fp = popen(cmd.c_str(), "r");
//     if (fp == nullptr)
//     {
//         respon_message = cmd + " exec failed";
//     }
//     char line[1024];
//     while (fgets(line, sizeof(line) - 1, fp))
//     {
//         respon_message += line;
//     }
//     pclose(fp);

//     // 开始返回
//     struct sockaddr_in client;
//     bzero(&client, 0);
//     client.sin_family = AF_INET;
//     client.sin_addr.s_addr = inet_addr(clientip.c_str());
//     client.sin_port = htons(clientport);
//     sendto(sockfd, respon_message.c_str(), respon_message.size(), 0, (struct sockaddr *)&client, sizeof(client));
// }

OnlineUser onlineuser;

// demo3
void routeMessage(int sockfd, string clientip, uint16_t clientport, string message)
{
    // 用户要发消息，先上线
    if (message == "online")
        onlineuser.addUser(clientip, clientport); // 添加用户
    if (message == "offline")
        onlineuser.delUser(clientip, clientport);
    // 判断用户是否在线
    if (onlineuser.isOnline(clientip, clientport)) // 如果用户在线
    {
        // 消息路由
        // 服务器收到用户消息，将用户消息给所有在线用户,包括自己，转发过去，广播消息
        onlineuser.boardcastMessage(sockfd, clientip,clientport,message); // 当给在线用户转发消息的时候，其实并不是只有用户发的消息，例如还有用户昵称、头像、时间...等，可以在User里添加，boardcastMessage转发消息的时候，做一下昵称与消息的拼接即可。
    }
    else // 如果用户不在线，给用户单独发消息，提示用户上线
    {
        struct sockaddr_in client;
        bzero(&client, sizeof(client));
        client.sin_family = AF_INET;
        client.sin_addr.s_addr = inet_addr(clientip.c_str());
        client.sin_port = htons(clientport);
        string respon_message = "你还未上线，请先上线，运行：online";
        sendto(sockfd, respon_message.c_str(), respon_message.size(), 0, (struct sockaddr *)&client, sizeof(client));
    }
}

//./udpServer port
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);

    // signal(2, reload);
    // initDict();
    // debugPrint(); // 测试切割

    // std::unique_ptr<udpServer> usvr(new udpServer(handlerMessage, port));
    // std::unique_ptr<udpServer> usvr(new udpServer(execCommond, port));

    std::unique_ptr<udpServer> usvr(new udpServer(routeMessage, port));

    usvr->initServer();
    usvr->start();

    return 0;
}